package mybatis.sharding.quickstart.cfg;

import java.lang.reflect.Method;
import java.util.List;

import org.apache.ibatis.binding.BindingException;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

public class MyBatisConfigurationsWrapper extends Configuration{
    
    private final Configuration configuration;

    private final List<SqlSessionFactory> sqlSessionFactories;

    public MyBatisConfigurationsWrapper(Configuration configuration,List<SqlSessionFactory> sqlSessionFactories) {
        this.configuration = configuration;
        this.sqlSessionFactories = sqlSessionFactories;
    }

    @Override
    public Environment getEnvironment() {
        return configuration.getEnvironment();
    }

    @Override
    public ExecutorType getDefaultExecutorType() {
        return configuration.getDefaultExecutorType();
    }

    @Override
    public ObjectFactory getObjectFactory() {
        return configuration.getObjectFactory();
    }

    @Override
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        for (SqlSessionFactory sqlSessionFactory : getSqlSessionFactories()) {
            T mapper = null;
            try {
                mapper = sqlSessionFactory.getConfiguration().getMapper(type, sqlSession);
            } catch (BindingException e) {
                // ignore exception
            }

            if (mapper != null) {
                return mapper;
            }
        }

        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");

    }
    
    @Override
    public boolean hasMapper(Class<?> type) {
        for (SqlSessionFactory factory : getSqlSessionFactories()) {
            if (factory.getConfiguration().hasMapper(type)) {
                return true;
            }
        }

        return false;
    }

    @Override
    public MappedStatement getMappedStatement(String id) {
        Exception exception = null;
        MappedStatement mappedStatement = null;
        for (SqlSessionFactory sqlSessionFactory : getSqlSessionFactories()) {
            try {
                mappedStatement = sqlSessionFactory.getConfiguration().getMappedStatement(id);
            } catch (Exception e) {
                // ignore exception
                exception = e;
            }

            if (mappedStatement != null) {
                return mappedStatement;
            }
        }

        throw new BindingException("Invalid bound statement (not found): " + id, exception);
    }

    @Override
    public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {

        if (validateIncompleteStatements) {
            buildAllStatements();
        }

        for (SqlSessionFactory sqlSessionFactory : getSqlSessionFactories()) {
            try {
                boolean has = sqlSessionFactory.getConfiguration().getMappedStatementNames().contains(statementName);

                if(has) {
                    return true;
                }
            } catch (Exception e) {
                // ignore exception
            }
        }

        return false;

    }

    @Override
    protected void buildAllStatements() {
        for (SqlSessionFactory sqlSessionFactory : getSqlSessionFactories()) {
            try {
                Configuration configuration = sqlSessionFactory.getConfiguration();

                Method m = Configuration.class.getDeclaredMethod("buildAllStatements");
                m.setAccessible(true);
                m.invoke(configuration);
            } catch (Exception e) {
                // ignore exception
            }
        }


    }

    public Configuration getConfiguration() {
        return configuration;
    }

    public List<SqlSessionFactory> getSqlSessionFactories() {
        return sqlSessionFactories;
    }
    
    
    
}
